package com.atguigu.biz.service.impl;

import com.atguigu.biz.common.config.RuoYiConfig;
import com.atguigu.biz.common.constant.Constants;
import com.atguigu.biz.common.utils.StringUtils;
import com.atguigu.biz.common.utils.uuid.UUID;
import com.atguigu.biz.domain.BizKnowledge;
import com.atguigu.biz.service.IEmbeddingStoreService;
import dev.langchain4j.data.document.DefaultDocument;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.Metadata;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.*;
import dev.langchain4j.store.embedding.filter.comparison.IsIn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;


/**
 * @author kkdulx
 * @date 2025/10/31
 */

@Service
public class EmbeddingStoreServiceImpl implements IEmbeddingStoreService {

    @Autowired
    private EmbeddingModel embeddingModel;

    @Autowired
    private EmbeddingStore embeddingStore;

    @Override
    public void upload(BizKnowledge bizKnowledge) {

        //content：
        // /profile/upload/2025/08/06/医院信息_20250806065938A001.md,/profile/upload/2025/08/06/神经内科_20250806065955A002.md

        //文件下载路径：
        // http://localhost/dev-api/profile/upload/2025/08/06/医院信息_20250806065938A001.md


        // 从业务对象中获取内容（文件路径列表）
        System.out.println("上传知识库---");
        String content = bizKnowledge.getContent();
        String[] fileList = content.split(",");

        // 存储生成的向量ID列表，用于后续删除业务对象
        List<String> vectorIdList = new ArrayList<>();
        // 存储上传的文档集合，准备进行向量化
        List<Document> documents = new ArrayList<>();

        // 遍历每个文件路径，处理并添加到文档集合
        for (String file : fileList) {
            // 获取文件存储的基础路径
            String profilePath = RuoYiConfig.getProfile();

            // 移除路径前缀，获取相对路径
            file = StringUtils.substringAfter(file, Constants.RESOURCE_PREFIX);

            // 从文件系统加载文档并解析为Document对象
            Document document = FileSystemDocumentLoader.loadDocument(profilePath + file);

            // 复制原始文档的元数据，并添加自定义vectorId
            Map<String, Object> newMetadataMap = document.metadata().toMap();

            // 生成唯一的向量ID
            String uuid = UUID.randomUUID().toString();
            vectorIdList.add(uuid);

            // 将向量ID添加到元数据中，用于后续检索和删除
            newMetadataMap.put("vectorId", uuid);
            Metadata metadata = Metadata.from(newMetadataMap);

            // 创建新的Document实例，保留原文内容但替换元数据
            Document newDocument = new DefaultDocument(
                    // 保持原文内容不变
                    document.text(),

                    // 使用包含vectorId的元数据
                    metadata
            );
            documents.add(newDocument);
        }
            // 将文档集合进行向量化并存储到向量数据库
            // EmbeddingStoreIngestor会自动将文档分割为片段，生成嵌入向量，并存储到向量库
        EmbeddingStoreIngestor
                .builder()
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .build()
                .ingest(documents);

            // 更新业务对象，将生成的vectorId列表保存到数据库
        bizKnowledge.setVectorIds(StringUtils.join(vectorIdList, ","));
    }

    @Override
    public void remove(List<String> vectorIdList) {
        if (vectorIdList == null || vectorIdList.isEmpty()) {
            return;
        }

        // 创建一个与索引维度匹配的虚拟查询向量（全零向量）
        //在向量数据库查询中，全零向量（或虚拟向量）的作用是绕过相似度计算，仅基于元数据过滤条件进行查询。
        List<Float> dummyVector = Collections.nCopies(embeddingModel.dimension(), 0.0F);
        Embedding queryEmbedding = Embedding.from(dummyVector);


        // 构建搜索请求
        EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
                .queryEmbedding(queryEmbedding)
                .filter(new IsIn("vectorId", vectorIdList))
                .maxResults(10000) //默认是3，取值范围1- 10000
                .build();

        // 执行搜索
        EmbeddingSearchResult result = embeddingStore.search(request);
        List<EmbeddingMatch<TextSegment>> matches  = result.matches();
        System.out.println("查询条件: " + vectorIdList);
        System.out.println("匹配到的数量: " + matches.size());
        for (EmbeddingMatch<TextSegment> match : matches) {
            System.out.println("匹配ID: " + match.embeddingId());
            System.out.println("元数据: " + match.embedded().metadata());
            embeddingStore.remove(match.embeddingId());
        }
    }
}